#ifndef _FMM_H_
#define _FMM_H_

#define _USE_MATH_DEFINES //For openmesh
#define PI  3.14159265358
#define MAXIMUM 1e12
#define ERROR  1e-6

#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenMesh/Core/Mesh/Traits.hh>

enum STATE{ALIVE, CLOSE, FAR};

struct MeshTraits : public OpenMesh::DefaultTraits
{
  // store barycenter of neighbors in this member
  VertexTraits
  {
  private:
    double geo_dist;
	STATE state; 
  public:

    VertexT() : geo_dist( MAXIMUM ), state (FAR) { }

	double get_distance() const { return this->geo_dist; }
    void set_distance(const double & distance) { geo_dist = distance; }

	STATE get_state() const {return this->state;}
	void set_state (const STATE & s) {this->state = s;} 

  };
};

typedef OpenMesh::TriMesh_ArrayKernelT<MeshTraits>  Mesh;

class VertexQueueElement {
public:
	double distance;  
	Mesh::VertexHandle v_handle;
 //friend ostream& operator<<(ostream &, const Destination &) ;
public:

	VertexQueueElement (const Mesh::VertexHandle vh, double ds)
		: distance(ds), v_handle(vh) {}
 
	bool operator< (const 
		VertexQueueElement & right) const {
		return distance > right.distance; 
	}
};

int acute_local_solver (double T_A, double T_B, double a, double b, double c, double f_C, double & T_C);
int obtuse_local_solver (Mesh & mesh, Mesh::VertexHandle va, Mesh::VertexHandle vb, Mesh::VertexHandle vc, double fc, double & distance);
int fast_marching (Mesh & mesh, std::vector<Mesh::VertexHandle> & front);
double angle (double AB, double Bc, double CA);
double edge (double e1, double e2, double theta);
double flip(double AB, double BC, double AC, double AD, double BD);
#endif
